package pda.view;

import checkers.Checkers;
import checkers.Move;
import java.awt.*;
import java.awt.image.BufferStrategy;
import java.util.ArrayList;
import javax.swing.*;
import pda.control.CheckersCtrl;
import pda.datas.CheckersData;


public class CheckersView
{
    private static final int COL_NUM = 4;
    private static final Color LIGHT_BROWN = new Color(239, 228, 176);
    private static final Color DARK_BROWN = new Color(128,64,0);
    private final Color[] moveColors = new Color[COL_NUM];
    
    private CheckersData data;
    private JPanel panel;
    private MyCanvas canvas;
    
    private JMenuBar menu;
    public JMenu game = new JMenu("Game");
    public JMenuItem newGame = new JMenuItem("New game");
    public JMenuItem loadGame = new JMenuItem("Load game");
    public JMenuItem saveGame = new JMenuItem("Save game");
    private JMenu boardSettings = new JMenu("Board");
    public JCheckBoxMenuItem showLastMovCheck = new JCheckBoxMenuItem("Show last move", true);
    public JCheckBoxMenuItem showValidCheck = new JCheckBoxMenuItem("Show legal moves", false);
    public JCheckBoxMenuItem showNumbersCheck = new JCheckBoxMenuItem("Show numbers", false);
    public JCheckBoxMenuItem flipBoardCheck = new JCheckBoxMenuItem("Flip board", false);
    public JCheckBoxMenuItem editPosCheck = new JCheckBoxMenuItem("Edit position", false);
    public JMenuItem emptyBoard = new JMenuItem("Empty board");
    private JMenu aiSettings = new JMenu("AI settings");
    public JCheckBoxMenuItem ai1Check = new JCheckBoxMenuItem("White is AI", false);
    public JCheckBoxMenuItem ai2Check = new JCheckBoxMenuItem("Black is AI", true);
    public JMenuItem moveNow = new JMenuItem("Move now");
    private JMenu depth = new JMenu("depth");
    private ButtonGroup depthGroup = new ButtonGroup();
    private JRadioButtonMenuItem[] depthValues = new JRadioButtonMenuItem[6];
    public TurnItem turn = new TurnItem("Turn:        ");
    
    private Point[] coords;
    private static final int SCREEN_WIDTH = 318;
    private static final int MENU_SIZE = 18;
    private static final int CANVAS_SIZE = 300;
    private int squareSize;
    private int pieceSize;
    private int queenSize;
    private int space;
    
    public int dragSquare = -1;
    public int destSquare = -1;
    public int dragPiece;
    public int dragX, dragY;
    
    public int[] lastMoveSquares = null;
    public int[] lastMoveCapSquares = null;
    public ArrayList<Integer> validSquares = new ArrayList<Integer>();
    public boolean showLastMove = true;
    public boolean showValidMoves = false;
    public boolean showNumbers = false;
    public boolean flipBoard = false;
    
    private class MyCanvas extends Canvas
    {

        public MyCanvas(int width, int height)
        {
            setSize(width, height);
        }

        public void drawPiece(int piece, int x, int y, int offset, Graphics g)
        {
            if(piece == Checkers.EMPTY) return;

            if(piece == Checkers.BLACK_PAWN || piece == Checkers.BLACK_QUEEN)
                g.setColor(Color.BLACK);
            else
                g.setColor(Color.WHITE);

            g.fillArc(x+offset, y+offset, pieceSize, pieceSize, 0, 360);
            
            if(piece == Checkers.WHITE_QUEEN || piece == Checkers.BLACK_QUEEN)
            {
                g.setColor(Color.YELLOW);
                ((Graphics2D)g).setStroke(new BasicStroke(queenSize));
                g.drawArc(x+offset, y+offset, pieceSize, pieceSize, 0, 360);
                ((Graphics2D)g).setStroke(new BasicStroke(1));
            }
        }
        
        public void drawBoard(Graphics g)
        {
            for(int i=1; i<coords.length; ++i)
            {
                Point p = squareToCoord(i);
                g.setColor(DARK_BROWN);
                g.fillRect(p.x, p.y, squareSize, squareSize);
                if(dragSquare != i) drawPiece(data.check.getSquare(i), p.x, p.y, space, g);
            }        
        }
        
        public void drawLastMove(Graphics g)
        {
            if(lastMoveCapSquares != null)
            {
                g.setColor(Color.RED);
                for(int i=0; i<lastMoveCapSquares.length; ++i)
                {
                    Point p = squareToCoord(lastMoveCapSquares[i]);
                    g.fillRect(p.x, p.y, squareSize, squareSize);
                }
            }
            
            if(lastMoveSquares != null)
            {
                ((Graphics2D)g).setStroke(new BasicStroke(2));
                g.setColor(Color.YELLOW);
                for(int i=0; i<lastMoveSquares.length; ++i)
                {
                    Point p1 = squareToCoord(lastMoveSquares[i]);
                    Point p2 = squareToCoord(lastMoveSquares[++i]);
                    g.drawLine(p1.x+squareSize/2, p1.y+squareSize/2, p2.x+squareSize/2, p2.y+squareSize/2);
                }
            }
        }
        
        public void drawValidMoves(Graphics g)
        {
            if(data.isAiTurn() || data.check.getStatus()>0) return;
            
            if(dragSquare > 0 && validSquares.contains(dragSquare))
            {
                g.setColor(Color.CYAN);
                ((Graphics2D)g).setStroke(new BasicStroke(3));
                Point p = squareToCoord(dragSquare);
                g.drawRect(p.x, p.y, squareSize, squareSize);
                
                g.setColor(Color.BLUE);
                for(Move m : data.check.validMoves)
                {
                    if(m.start == dragSquare)
                    {
                        p = squareToCoord(m.dest);
                        g.drawRect(p.x, p.y, squareSize, squareSize);
                    }   
                }
                
                if(destSquare <= 0) return;
                ((Graphics2D)g).setStroke(new BasicStroke(2));
                ArrayList<Move> moves = data.check.getPlayerMove(dragSquare, destSquare);
                int col = 0;
                for(Move m : moves)
                {
                    int[] moveSquares = m.getSquares();
                    g.setColor(moveColors[col]);
                    for(int i=0; i<moveSquares.length; ++i)
                    {
                        Point p1 = squareToCoord(moveSquares[i]);
                        Point p2 = squareToCoord(moveSquares[++i]);
                        g.drawLine(p1.x+squareSize/2, p1.y+squareSize/2, p2.x+squareSize/2, p2.y+squareSize/2);
                    }
                    col = (col==COL_NUM-1 ? 0 : col+1);
                }
            }
            else
            {
                g.setColor(Color.CYAN);
                ((Graphics2D)g).setStroke(new BasicStroke(3));
                for(int i : validSquares)
                {
                    Point p = squareToCoord(i);
                    g.drawRect(p.x, p.y, squareSize, squareSize);
                }
            }
        }
        
        public void drawNumbers(Graphics g)
        {
            g.setColor(Color.GREEN);
            for(int i=1; i<coords.length; ++i)
            {
                Point p = squareToCoord(i);
                g.drawString(String.valueOf(i), p.x, p.y+10);
            }
        }

        public void paint(Graphics g)
        {
            drawBoard(g);
            if(showLastMove) drawLastMove(g);
            if(showValidMoves) drawValidMoves(g);
            if(showNumbers) drawNumbers(g);
            if(dragSquare != -1) drawPiece(dragPiece, dragX, dragY, -pieceSize/2, g);
            
        }

        public void update(Graphics g)
        {
            BufferStrategy bs = getBufferStrategy();
            Graphics dg = bs.getDrawGraphics();
            dg.setColor(LIGHT_BROWN);
            dg.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());
            paint(dg);
            bs.show();
        }
    }
    
    public class TurnItem extends JMenu
    {  
        public TurnItem(String title)
        {
            super(title);
        }

        public void paint(Graphics g)
        {
            super.paint(g);
            g.setColor( data.check.whiteToPlay() ? Color.WHITE : Color.BLACK );
            g.fillRect(40, 0, 50, 50);
        }
    }
    
    public CheckersView(CheckersCtrl ctrl, CheckersData data)
    {
        moveColors[0] = Color.BLUE;
        moveColors[1] = Color.CYAN;
        moveColors[2] = Color.MAGENTA;
        moveColors[3] = Color.PINK;
        JPopupMenu.setDefaultLightWeightPopupEnabled(false);
                
        this.data = data;
        panel = new JPanel();
        panel.setLayout(null);
        
        menu = new JMenuBar();
        menu.setSize(SCREEN_WIDTH, MENU_SIZE);
        menu.add(game);
        game.add(newGame);
        game.add(loadGame);
        game.add(saveGame);
        menu.add(boardSettings);
        boardSettings.add(showNumbersCheck);
        boardSettings.add(showLastMovCheck);
        boardSettings.add(showValidCheck);
        boardSettings.add(flipBoardCheck);
        boardSettings.add(new JSeparator());
        boardSettings.add(editPosCheck);
        boardSettings.add(emptyBoard);
        menu.add(aiSettings);
        aiSettings.add(ai1Check);
        aiSettings.add(ai2Check);
        aiSettings.add(moveNow);
        aiSettings.add(depth);
        for(int i=0, value=6; i<6; ++i, value+=2)
        {
            depthValues[i] = new JRadioButtonMenuItem(Integer.toString(value), false);
            depthValues[i].addActionListener(ctrl);
            depthGroup.add(depthValues[i]);
            depth.add(depthValues[i]);
        }
        depthValues[3].setSelected(true);
        menu.add(Box.createHorizontalGlue());
        menu.add(turn);
        panel.add(menu);
        
        canvas = new MyCanvas(300, 300);
        updateDrawSizes();
        canvas.addMouseListener(ctrl);
        canvas.addMouseWheelListener(ctrl);
        canvas.addMouseMotionListener(ctrl);
        canvas.setFont(new Font("Comic Sans MS", Font.BOLD, 10));
        panel.add(canvas);
   
        newGame.addActionListener(ctrl);
        loadGame.addActionListener(ctrl);
        saveGame.addActionListener(ctrl);
        showNumbersCheck.addActionListener(ctrl);
        showLastMovCheck.addActionListener(ctrl);
        showValidCheck.addActionListener(ctrl);
        flipBoardCheck.addActionListener(ctrl);
        editPosCheck.addActionListener(ctrl);
        emptyBoard.addActionListener(ctrl);
        ai1Check.addActionListener(ctrl);
        ai2Check.addActionListener(ctrl);
        moveNow.addActionListener(ctrl);
        turn.addMouseListener(ctrl);
        
        canvas.setBackground(LIGHT_BROWN);
        emptyBoard.setEnabled(false);
    }
    
    public void createCoords()
    {
        coords = new Point[data.check.squaresNum+1];
        boolean even = false;
        int x = squareSize, y = 0;

        for(int i=1; i<coords.length; ++i)
        {
            coords[i] = new Point(x, y);
            x += squareSize*2;

            if(i%(data.check.size/2) == 0)
            {
                x = (even^=true) ? 0 : squareSize;
                y += squareSize;
            }
        }        
    }
    
    public void updateDrawSizes()
    {
        squareSize = CANVAS_SIZE/data.check.size;
        pieceSize = squareSize - (int)Math.ceil((squareSize*0.15));
        queenSize = 4+(10-data.check.size);
        if(queenSize<1) queenSize = 1;
        space = (int)Math.ceil((squareSize*0.06));
        createCoords();
        
        canvas.setSize(squareSize*data.check.size, squareSize*data.check.size);
        canvas.setLocation((SCREEN_WIDTH-canvas.getWidth())/2,
                MENU_SIZE+1+((CANVAS_SIZE-canvas.getHeight())/2));
    }
    
    public JPanel getPanel()
    {
        return panel;
    }
    
    public void createBuffers()
    {
        canvas.createBufferStrategy(2);
    }
    
    public int coordToSquare(int x, int y)
    {
        if(x>=canvas.getWidth() || y>=canvas.getHeight() || x<0 || y<0) return -1;
        
        int row = y/squareSize;
        int col = x/squareSize;
        int square = (data.check.size*row+col) + 1;

        if((row%2)==0)
        {
            int res = square/2;
            if((square%2)==0)
                return (flipBoard ? coords.length-res : res);
        }
        else
        {
            int res = square/2+1;
            if((square%2)!=0)
                return (flipBoard ? coords.length-res : res);
        }

        return -1;
    }
    
    public Point squareToCoord(int square)
    {
        return flipBoard ? coords[coords.length-square] : coords[square];
    }
    
    public void updateDragCoord(Point p)
    {
        if(dragSquare == -1) return;
        dragX = p.x;
        dragY = p.y;
        canvas.repaint();
    }
    
    public boolean isDragging()
    {
        return dragSquare != -1;
    }
    
    public void incrementDragPiece()
    {
       ++dragPiece;
       if(dragPiece > 3) dragPiece = 0;
       canvas.repaint();
    }
    
    public void decrementDragPiece()
    {
       --dragPiece;
       if(dragPiece < 0) dragPiece = 3;
       canvas.repaint();
    }
    
    public void toggleLastMove()
    {
        showLastMove ^= true;
        canvas.repaint();
    }

    public void toggleNumbers()
    {
        showNumbers ^= true;
        canvas.repaint();
    }
    
    public void updateLastMove(int[] squares, int[] capSquares)
    {
        lastMoveSquares = squares;
        lastMoveCapSquares = capSquares;
    }
    
    public void updateScreen()
    {
        turn.repaint();
        canvas.repaint();
    }
}